package jmini.dao;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jmini.annotation.AP_FIELD;
import jmini.annotation.AP_MODEL;
import jmini.annotation.AP_ONE2MANY;
import jmini.modules.Module;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.StringUtils;

public class ApModelRowMapper<T> implements RowMapper<T>{
	
	public final Logger log = LoggerFactory.getLogger(ApModelRowMapper.class);
	
	//是否处理外键关联字段，为止循环关联，只处理第一层的外键关联信息
	private Boolean isDealOne2Many = true;
	
	/** 用来映射的model子类 */
	private Class<T> mappedClass;
	
	private Map<String, Field> mappedFields = new HashMap<String, Field>();
	
	private List<Field> one2ManyFields = new ArrayList<Field>();
	
	private Map<String, Object> one2OneFieldNameMap = new HashMap<String, Object>();
	
	private MiniDAO simpleDAO = null;
	
	public ApModelRowMapper(Class<T> mappedClass, MiniDAO dao, Boolean isDealOne2Many) {
		this.isDealOne2Many = isDealOne2Many;
		this.mappedClass = mappedClass;
		simpleDAO = dao;
		//处理保留字段
//		try {
//			//找到modelClass
//			@SuppressWarnings("rawtypes")
//			Class modelClass = mappedClass;
//			@SuppressWarnings("rawtypes")
//			Class curClass = mappedClass;
//			for(; curClass != Object.class; curClass = modelClass.getSuperclass()){
//				if(curClass == DataModel.class){
//					modelClass = curClass;
//				}
//			}
//			Field id_field = modelClass.getDeclaredField("id");
//			Field createdate_field = modelClass.getDeclaredField("createDate");
//			Field createuid_field = modelClass.getDeclaredField("createUid");
//			Field writedate_field = modelClass.getDeclaredField("writeDate");
//			Field writeuid_field = modelClass.getDeclaredField("writeUid");
//			
//			mappedFields.put("ID", id_field);
//			mappedFields.put("CREATE_DATE", createdate_field);
//			mappedFields.put("CREATE_UID", createuid_field);
//			mappedFields.put("WRITE_DATE", writedate_field);
//			mappedFields.put("WRITE_UID", writeuid_field);
//			
//		} catch (NoSuchFieldException e) {
//			log.error("get field fail",e);
//		} catch (SecurityException e) {
//			log.error("get field fail",e);
//		}
		
		//处理注释字段
		if(mappedClass.isAnnotationPresent(AP_MODEL.class)){
			Field[] fields = mappedClass.getDeclaredFields();
			for(Field field : fields){
				if(field.isAnnotationPresent(AP_FIELD.class)){
					AP_FIELD apfield = (AP_FIELD)field.getAnnotation(AP_FIELD.class);
					if(!StringUtils.isEmpty(apfield.fieldName())){
						mappedFields.put(apfield.fieldName(), field);
					}
				}
				//如果是外键关联字段
				if(this.isDealOne2Many == true && isDealOne2Many == field.isAnnotationPresent(AP_ONE2MANY.class)){
					one2ManyFields.add(field);
					AP_ONE2MANY afield = (AP_ONE2MANY)field.getAnnotation(AP_ONE2MANY.class);
					//如何是一对一，记住字段名，在循环rs取值时获取他的值
					if(afield.isOne2One() == true){
						one2OneFieldNameMap.put(afield.fieldName(), null);
					}
				}
			}
		}
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public T mapRow(ResultSet rs, int rowNum) throws SQLException {
		T mappedObject = BeanUtils.instantiate(this.mappedClass);
		BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
		ResultSetMetaData rsmd = rs.getMetaData();
		
		int columnCount = rsmd.getColumnCount();
		for (int index = 1; index <= columnCount; index++) {
			String column = JdbcUtils.lookupColumnName(rsmd, index);
			Field curField = this.mappedFields.get(column);
			if (curField != null) {
				Object value = JdbcUtils.getResultSetValue(rs, index, curField.getType());
				bw.setPropertyValue(curField.getName(), value);
			}
			//设置固定保留字段的值
			if("ID".equals(column)){
				Object value = JdbcUtils.getResultSetValue(rs, index, String.class);
				bw.setPropertyValue("id", value);
			}
			
			if("CREATE_DATE".equals(column)){
				Object value = JdbcUtils.getResultSetValue(rs, index, Date.class);
				bw.setPropertyValue("createDate", value);
			}
			
			if("CREATE_UID".equals(column)){
				Object value = JdbcUtils.getResultSetValue(rs, index, String.class);
				bw.setPropertyValue("createUid", value);
			}
			
			if("WRITE_DATE".equals(column)){
				Object value = JdbcUtils.getResultSetValue(rs, index, Date.class);
				bw.setPropertyValue("writeDate", value);
			}
			
			if("WRITE_UID".equals(column)){
				Object value = JdbcUtils.getResultSetValue(rs, index, String.class);
				bw.setPropertyValue("writeUid", value);
			}
			
			for(String key : one2OneFieldNameMap.keySet()){
				if(key.equals(column)){
					Object one2oneid = JdbcUtils.getResultSetValue(rs, index, String.class);
					one2OneFieldNameMap.put(key, one2oneid);
				}
			}
		}
		//处理One2Many类型字段
		if(one2ManyFields != null && one2ManyFields.size() > 0){
			@SuppressWarnings("rawtypes")
			Class modelType = null;
			String tableName = null;
			String fieldName = null;
			String sqlwhere = null;
			String sqlorderby = null;
			boolean isOne2One = false;
			for(int i = 0; i < one2ManyFields.size(); i++){
				Field cfield = one2ManyFields.get(i);
				AP_ONE2MANY afield = (AP_ONE2MANY)cfield.getAnnotation(AP_ONE2MANY.class);
				modelType = afield.modelType();
				if(modelType.isAnnotationPresent(AP_MODEL.class)){//如果对象也是个模型
					AP_MODEL modelAp = (AP_MODEL)modelType.getAnnotation(AP_MODEL.class);
					tableName = modelAp.tableName();
					fieldName = afield.fieldName();
					sqlwhere = afield.sqlWhere();
					sqlorderby = afield.sqlOrderBy();
					isOne2One = afield.isOne2One();
					if(!StringUtils.isEmpty(tableName) && !StringUtils.isEmpty(fieldName) && simpleDAO != null){
						if(isOne2One == true){//一对一
							if(!StringUtils.isEmpty(sqlwhere)){
								sqlwhere = "ID=? AND " + sqlwhere + " ";
							}else{
								sqlwhere = "ID=? ";
							}
							List<Module> sublist = simpleDAO.queryList(sqlwhere, sqlorderby, modelType, false, one2OneFieldNameMap.get(fieldName));
							if(sublist != null && sublist.size() > 0){
								bw.setPropertyValue(cfield.getName(), sublist.get(0));
							}
						}else{//一对多
							if(!StringUtils.isEmpty(sqlwhere)){
								sqlwhere = fieldName + "=? AND " + sqlwhere + " ";
							}else{
								sqlwhere = fieldName + "=? ";
							}
							List<Module> sublist = simpleDAO.queryList(sqlwhere, sqlorderby, modelType, false, bw.getPropertyValue("id"));
							bw.setPropertyValue(cfield.getName(), sublist);
						}
					}
				}
			}
		}
		return mappedObject;
	}

}
